{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Linear Regression"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will follow the example given by [scikit-learn](https://scikit-learn.org/stable/auto_examples/linear_model/plot_ols.html), and use the [diabetes](https://www4.stat.ncsu.edu/~boos/var.select/diabetes.html) dataset to train and test a linear regressor. We begin by loading the dataset (using only two features for this example) and splitting it into training and testing samples (an 80/20 split)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train examples: 353, Test examples: 89\n"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn import datasets\n",
    "\n",
    "dataset = datasets.load_diabetes()\n",
    "X_train, X_test, y_train, y_test = train_test_split(dataset.data[:, :2], dataset.target, test_size=0.2)\n",
    "print(\"Train examples: %d, Test examples: %d\" % (X_train.shape[0], X_test.shape[0]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Non-private baseline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We now use scikit-learn's native LinearRegression function to establish a non-private baseline for our experiments. We will use the [r-squared score](https://en.wikipedia.org/wiki/Coefficient_of_determination) to evaluate the goodness-of-fit of the model, which is built into LinearRegression. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Non-private baseline R2 score: 0.06\n"
     ]
    }
   ],
   "source": [
    "from sklearn.linear_model import LinearRegression as sk_LinearRegression\n",
    "\n",
    "regr = sk_LinearRegression()\n",
    "regr.fit(X_train, y_train)\n",
    "baseline = regr.score(X_test, y_test)\n",
    "print(\"Non-private baseline R2 score: %.2f\" % baseline)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Differentially private Linear Regression"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's now train a differentially private linear regressor, where the trained model is differentially private with respect to the training data. We will pass additional hyperparameters to the regressor later to suppress the `PrivacyLeakWarning`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "R2 score for epsilon=1.00: -0.02\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      ".../site-packages/diffprivlib/models/linear_regression.py:262: PrivacyLeakWarning: Bounds parameters haven't been specified, so falling back to determining bounds from the data.\n",
      "This will result in additional privacy leakage. To ensure differential privacy with no additional privacy loss, specify `bounds_X` and `bounds_y`.\n",
      "  PrivacyLeakWarning)\n"
     ]
    }
   ],
   "source": [
    "from diffprivlib.models import LinearRegression\n",
    "\n",
    "regr = LinearRegression()\n",
    "regr.fit(X_train, y_train)\n",
    "\n",
    "print(\"R2 score for epsilon=%.2f: %.2f\" % (regr.epsilon, regr.score(X_test, y_test)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Plotting r-squared versus epsilon"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We want to evaluate the tradeoff between goodness-of-fit and privacy budget (epsilon), and plot the result using `matplotlib`. For this example, we evaluate the score for epsilon between 1e-2 and 1e2. To ensure no privacy leakage from the hyperparameters of the model, `data_norm`, `range_X` and `range_y` should all be set independently of the data, i.e. using domain knowledge. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "epsilons = np.logspace(-1, 2, 100)\n",
    "accuracy = []\n",
    "\n",
    "for epsilon in epsilons:\n",
    "    regr = LinearRegression(epsilon=epsilon, bounds_X=(-0.138, 0.2), bounds_y=(25, 346))\n",
    "    regr.fit(X_train, y_train)\n",
    "    \n",
    "    accuracy.append(regr.score(X_test, y_test))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And then plot the result in a semi-log plot."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x7f4e60f2ec88>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "plt.semilogx(epsilons, accuracy, label=\"Differentially private linear regression\", zorder=10)\n",
    "plt.semilogx(epsilons, baseline * np.ones_like(epsilons), dashes=[2,2], label=\"Non-private baseline\", zorder=5)\n",
    "plt.xlabel(\"epsilon\")\n",
    "plt.ylabel(\"r-squared score\")\n",
    "plt.ylim(-5, 1.5)\n",
    "plt.xlim(epsilons[0], epsilons[-1])\n",
    "plt.legend(loc=2)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
